import RESTify, { Next, Request, Response } from "restify";
import errors from "restify-errors";
import { app as Goods } from "@src/apps/goods";
import { config } from "@src/config";
import { logger } from "@src/logger";
import { DatabaseManager } from "@src/lib/db/postgres";
export class Server {
	readonly server: RESTify.Server;
	private readonly databaseManager: DatabaseManager;
	private readonly entities: Function[] = [];
	private readonly initializations: Function[] = [];

	constructor() {
		this.server = RESTify.createServer({
		  log: logger,
		  name: config.server.name,
		  strictNext: true
		});
		this.databaseManager = new DatabaseManager();
	}
	
	async start(): Promise<void> {
		this.loadApps();
		await this.initDatabase();
		this.initRouter();
		this.handleError();
		this.handlePM2();
	
		this.server.listen(config.server.port, () => {
		  logger.info("%s listening at %s", this.server.name, this.server.url);
		  if (process.send) {
			process.send("ready");
		  }
		});
	}
  private handleError(): void {
    // send all RestErrors directly back to client
    this.server.on(
      "restifyError",
      (req: Request, res: Response, err, callback) => {
        logger.error(err);
        if (err instanceof errors.RestError) {
          return res.send(err);
        }
        res.send(new errors.BadRequestError("invalid request"));
      }
    );

    // log uncaughtException and terminate the process, leave it to PM2
    process.on("uncaughtException", err => {
      logger.error(err);
      process.exit(1);
    });
  }

  private handlePM2(): void {
    process.on("SIGINT", () => {
      logger.info("SIGINT signal received.");
      this.server.close(() => {
        this.databaseManager
          .close()
          .then(() => process.exit(0))
          .catch(() => process.exit(1));
      });
    });
  }

  private async initDatabase(): Promise<void> {
    await this.databaseManager.connect(this.entities);
    for (const initialization of this.initializations) {
      await initialization();
    }
  }

  private initRouter(): void {
    this.server.use(
      RESTify.plugins.bodyParser({
        mapParams: false
      })
    );
    this.server.use(RESTify.plugins.queryParser());
    this.server.use(RESTify.plugins.requestLogger());

    this.server.get("/", (req: Request, res: Response, next: Next) =>
      res.send(config.server.name)
    );
  }

  private loadApps(): void {
    // load system modules
    // Account(this.server, this.entities, this.initializations);
    Goods(this.server, this.entities, this.initializations);

  }
}